import datetime
from collections import defaultdict
from django.core.management.base import BaseCommand
from django.utils import timezone
from django_redis import get_redis_connection
from mongolog.models import CASLog, StrategyLog
from mongolog.utils import date_eq, date_range
from zmad.models import ZTPUser
from userdata.models import ActivityStatus, DailySummary
from userdata.training import adapters
from userdata.training.anomaly import AnomalyDetection
from ztp_backend.settings import WITH_WX


class Command(BaseCommand):
    help = "Collect and train user activity data to recognize anomaly activities."

    def add_arguments(self, parser):
        parser.add_argument('--outlier', type=int)
        parser.add_argument('--days', type=int)

    def handle(self, *args, **options):
        outlier = options['outlier'] or 500
        days = options['days'] or 15

        redis = get_redis_connection('anomaly_detection')
        adapter = adapters.RedisAdapter(redis)
        ad_model = AnomalyDetection(max_data=100, min_data=1, outlier=outlier, adapter=adapter)

        # 将前一天活跃情况入库
        yesterday = datetime.date.today() - datetime.timedelta(days=1)
        if WITH_WX:
            users = ZTPUser.objects.filter(enabled=True).exclude(wx_user_id="").values_list('username', flat=True)
        else:
            users = ZTPUser.objects.filter(enabled=True).values_list('username', flat=True)
        active_users = set(CASLog.objects.mongo_distinct(
            'username',
            {
                **date_eq('log_time', yesterday),
                'auth_code': 7,
                'username': {
                    '$exists': True,
                    '$ne': ''
                }
            }
        ))
        # abnormal_users = set(ad_model.anomaly_list())
        abnormal_users = set(StrategyLog.objects.mongo_distinct(
                'username',
                {
                    'username': {
                        '$exists': True,
                        '$ne': ''
                    },
                    **date_eq('log_time', yesterday),
                    "uid": {"$ne": "STG/AUTH-3"}
                }
            ))
        for username in users:
            ActivityStatus.objects.update_or_create(user_id=username, defaults={
                'is_active': username in active_users,
                'is_abnormal': username in abnormal_users,
            })

        DailySummary.objects.create(
            date=yesterday,
            total=len(users),
            active=len(active_users),
            inactive=len(users) - len(active_users),
            abnormal=len(abnormal_users)
        )

        # 重新生成训练数据
        ad_model.clear()
        train_data = self.count_user_activity(days)
        ad_model.train(train_data)

    def count_user_activity(self, days=15):
        """收集最近15天用户活动"""
        today = datetime.date.today()
        tz_name = timezone.get_default_timezone_name()
        queryset = CASLog.objects.mongo_aggregate([
            {
                '$match': {
                    'username': {
                        '$exists': True,
                        '$ne': ''
                    },
                    **date_range('log_time', date_from=today - datetime.timedelta(days=days))
                }
            },
            {
                '$group': {
                    '_id': {
                        'username': '$username',
                        'year': {'$year': {'date': '$log_time', 'timezone': tz_name}},
                        'month': {'$month': {'date': '$log_time', 'timezone': tz_name}},
                        'day': {'$dayOfMonth': {'date': '$log_time', 'timezone': tz_name}},
                    },
                    'count': {'$sum': 1}
                }
            },
            {
                '$project': {
                    '_id': 0,
                    'username': '$_id.username',
                    'date': ['$_id.year', '$_id.month', '$_id.day'],
                    'count': 1
                }
            }
        ])
        # 组装数据，过滤掉周末
        user2count = defaultdict(list)
        for agg in queryset:
            date = datetime.date(*agg['date'])
            if date.weekday() in [5, 6]:
                continue
            user2count[agg['username']].append(agg['count'])
        return user2count
